<template>
  <div>
    <label 
      v-if="label"
      :class="{ 'y-form-item-label-required': isRequired }"
    >
      {{ label }}
    </label>
    <div>
      <slot></slot>
      <div 
        class="y-form-item-message"
        v-if="validateState === 'error'"
      >
        {{ validateMessage }}
      </div>
    </div>
  </div>
</template>

<script>
import Emitter from 'common/commonJS/emitter.js';
import AsyncValidator from 'async-validator';

export default {
  name: "yFormItem",
  mixins: [Emitter],
  inject: ['form'], // 为了拿到Form中 model的数据。
  props: {
    label: {
      type: String,
      default: '',
    },
    // 当前的数据
    prop: {
      type: String,
    },
  },
  data() {
    return {
      isRequired: false,     // 是否必填
      validateState: '',     // 效验状态
      validateMessage: ''    // 效验不通过时提示的信息
    }
  },

  // 组件渲染时，将实例缓存在 form 中
  mounted() {
    // 如果没有传入 prop, 则无需校验，也就无需缓存
    if (this.prop) {
      this.dispatch('yForm', 'on-form-item-add', this);
      
      this.initialValue = this.fieldValue; // 设置初始值, 以便重置时恢复默认值
      
      this.setRules(); // 当prop有数据,则对 “当前的数据” 进行一次效验
    }
  },

  computed: {
    // 从 Form 的 model中动态获取当前组件的数据
    fieldValue() {
      return this.form.model[this.prop];
    }
  },
  methods: {
    // 监听表单两个事件，并绑定两个句柄函数。
    setRules () {
      let rules = this.getRules();
      if(rules.length) {
        rules.every( element => {
          this.isRequired = element.required; // 如果当前校验规则中有必填项，则标记出来
        })
      }

      this.$on('on-form-blur', this.onFieldBlur);
      this.$on('on-form-change', this.onFieldChange);
    },
    
    // 从 Form 的 rules 属性中，获取当前 FormItem 的效验规则
    getRules () {
      let formRules = this.form.rules;
      formRules = formRules ? formRules[this.prop] : [];
      return [].concat(formRules || []);
    },

    // 只支持 blur 和 change，所以过滤符合要求的 rule规则
    getFilteredRule (trigger) {
      const rules = this.getRules();
      return rules.filter(rule => {
        return !rule.trigger || (rule.trigger.indexOf(trigger) !== -1);
      })
    },
    // 重置数据
    resetField () {
      this.validateState = '';
      this.validateMessage = '';

      this.form.model[this.prop] = this.initialValue;
    },

    /**
     * 主要: 1. 设置当前的效验状态和效验不通过提示信息。
     *       2. 将 validateMessage 通过回调 callback 传递给调用者.
     */
    validate(trigger, callback = function() {}) {
      /**
       * 效验数据
       * @param { trigger: '效验类型', callback: '回调函数' }
       * 
      */
      let rules = this.getFilteredRule(trigger);

      if(!rules || rules.length === 0) {
        return true;
      }
      // 设置状态为效验中
      this.validateState = 'validating';

      // 以下为 async-validator 库的调用方法
      let descriptor = {};
      descriptor[this.prop] = rules;
      
      const validator = new AsyncValidator(descriptor);
      let model = {};

      model[this.prop] = this.fieldValue;

      validator.validate(model, { firstFields: true }, errors=> {
        this.validateState = !errors ? 'success' : 'error';
        this.validateMessage = errors ? errors[0].message : '';

        callback(this.validateMessage);
      });
    },

    onFieldBlur() {
      this.validate('blur');
    },
    onFieldChange() {
      this.validate('change');
    }
  },
  
  // 组件销毁前，将实例从 Form 的缓存中移出
  beforeDestroy() {
    this.dispatch('yForm', 'on-form-item-remove', this);
  },

};
</script>

<style>

label {
  font-size: 14px;
}
.y-form-item-label-required:before {
  content: '*';
  color: red;
}
.y-form-item-message {
  margin: 4px 2px;
  font-size: 15px;
  color: #e74c3c;
}
</style>